
// 全局通知
cc.Notification = {
    _eventMap: [],

    on: function(type, callback, target) {
        if (this._eventMap[type] === undefined) {
            this._eventMap[type] = [];
        }
        this._eventMap[type].push({ callback: callback, target: target });
    },

    emit: function(type, parameter) {
        var array = this._eventMap[type];
        if (array === undefined) return;

        for (var i = 0; i < array.length; i++) {
            var element = array[i];
            element && element.callback.call(element.target, parameter);
        }
    },

    off: function(type, callback) {
        var array = this._eventMap[type];
        if (array === undefined) return;

        for (var i = 0; i < array.length; i++) {
            var element = array[i];
            if (element && element.callback === callback) {
                array[i] = undefined;
                break;
            }
        }
    },

    offType: function(type) {
        this._eventMap[type] = undefined;
    },
};
// ------------------------------------ cc ------------------------------------
// 更美观的输出log
cc.logEx = function() {
    if (!CONFIG.test) {
        return;
    }
    var str = null;
    for (var i = 0; i < arguments.length; i++) {
        var element = arguments[i];
        if (typeof (element) === 'object') {
            element = JSON.stringify(element, function(key, value) {
                if (value instanceof cc.Component) {
                    return 'cc.Component:' + value.name;
                }
                else if (value instanceof cc.Node) {
                    return 'cc.Node:' + value.name;
                }
                return value;
            });
        }
        str = ((str === null) ? element : (str + ' ' + element));
    }
    cc.log(str);
}
// 动态加载url图片
cc.loadPng = function(url, callback, errCallback) {
    if (!url) return;
    if (url.indexOf('http') === -1) {
        url = CONFIG.baseUrl + url;
    }
    cc.logEx('动态加载url图片', url);
    // cc.loader.load({id:url, type:'png'}, (err, tex) => {
    cc.loader.load({ url: url, type: 'png' }, (err, tex) => {
        if (err) {
            cc.error('cc.loadPng加载失败');
            errCallback && errCallback(err);
            return;
        }
        else {
            callback(tex);
        }
    });
}
// 场景跳转，(注意：会先执行场景的onLoad之后再执行callback)
cc.loadScene = function(sceneName, callback) {
    if (callback) {
        cc.director.loadScene(sceneName, () => {
            var scriptComponent = cc.director.getScene().getChildByName('Canvas').getComponent(sceneName);
            if (scriptComponent) {
                callback(scriptComponent);
            }
            else {
                cc.logEx("找不到脚本：" + sceneName)
                cc.logEx("Scene脚本必须绑定在Scene的根节点，且脚本名必须与根节点名相同，才能传入参数")
            }
        });
    }
    else {
        cc.director.loadScene(sceneName);
    }
};
// 打开一个页面
cc.openUrl = function(url) {
    cc.logEx('打开链接', url);
    if (!url) return;
    window.location.href = url;
    // AppCall.navigate({
    //     id: 10006,
    //     category: 0,
    //     business: 0,
    //     param: GAME_URL[this._gameType],
    //     description: this.gameName[this._gameType-1]
    // });
    // cc.sys.openURL(GAME_URL[this._gameType]);
}
// ------------------------------------ array ------------------------------------
// 返回元素所在位置
window.array_indexOf = function(array, val) {
    for (var i = 0; i < array.length; i++) {
        if (array[i] == val) return i;
    }
    return -1;
}
// 删除元素
window.array_remove = function(array, val) {
    if (val === null) {
        return;
    }
    var index = array_indexOf(array, val);
    if (index > -1) {
        array.splice(index, 1);
    }
};
// 交换数组某两个元素
window.array_swap = function(array, index_1, index_2) {
    var temp = array[index_1];
    array[index_1] = array[index_2];
    array[index_2] = temp;
}
// 洗牌，返回新数组
window.array_shuffle = function(array) {
    var length = array.length;
    var shuffled = new Array(length);
    for (var index = 0, randIndex; index < length; index++) {
        randIndex = Math.rand(0, index);
        if (randIndex !== index) shuffled[index] = shuffled[randIndex];
        shuffled[randIndex] = array[index];
    }
    return shuffled;
}
// ------------------------------------ Node ------------------------------------
// 获取与当前节点同名的脚本
cc.Node.prototype.getScript = function() {
    return this.getComponent(this.name);
}
// 拷贝一份这个节点，并添加到相同的父节点下
cc.Node.prototype.copy = function() {
    var newNode = cc.instantiate(this);
    this.parent.addChild(newNode);
    return newNode;
}
// 查找node的子节点
cc.Node.prototype.find = function(path, componentType) {
    var node = cc.find(path, this);
    if (node && componentType) {
        return node.getComponent(componentType);
    }
    return node;
}
// 获得一个节点内位置在我所属坐标系的位置
cc.Node.prototype.nodeToMyParentSpacePosition = function(node, nodeSpacePos) {
    var pos = nodeSpacePos ? nodeSpacePos : cc.Vec2.ZERO;
    var nodeWordPos = node.convertToWorldSpaceAR(pos);
    var myParentSpacePosition = this.parent.convertToNodeSpaceAR(nodeWordPos);
    return myParentSpacePosition;
}
// 设置节点位置到该节点位置
cc.Node.prototype.setPositionByNode = function(node) {
    this.position = this.nodeToMyParentSpacePosition(node);
}
// 获取一个节点的世界坐标
cc.Node.prototype.getWordPosition = function() {
    return this.convertToWorldSpaceAR(cc.Vec2.ZERO);
}
// 获取节点世界坐标系的Rect，不受该节点是否被缩放或者旋转的影响
cc.Node.prototype.getRectToWord = function() {
    var wordPositon = this.convertToWorldSpace(cc.Vec2.ZERO);
    var size = this.getContentSize();
    var wordRect = cc.rect(wordPositon.x, wordPositon.y, size.width, size.height);
    return wordRect;
}
// 世界坐标点是否在node节点之内
cc.Node.prototype.containsPoint = function(point) {
    var wordRect = this.getRectToWord();
    if (wordRect.contains(point)) {
        // cc.logEx('intersectsPoint包含-true', this, wordRect, point);
        return true;
    }
    // cc.logEx('intersectsPoint包含-false', this, wordRect, point);
    return false;
}
// 与node节点是否相交
cc.Node.prototype.intersectsNode = function(node) {
    if (this === node) {
        return false;
    }
    var wordRect = this.getRectToWord();
    var node_wordRect = node.getRectToWord();
    if (wordRect.intersects(node_wordRect)) {
        // cc.logEx('intersectsNode相交-true', this, wordRect, node, node_wordRect);
        return true;
    }
    // cc.logEx('intersectsNode相交-false', this, wordRect, node, node_wordRect);
    return false;
}
// 与多个节点是否相交，返回所有相交中与自身靠的最近的那个
cc.Node.prototype.intersects = function(nodeArray) {
    var intersectsNodeArray = [];
    nodeArray.forEach((node) => {
        if (this.intersectsNode(node) === false) {
            return;
        }
        intersectsNodeArray.push(node);
    });
    if (intersectsNodeArray.length === 0) {
        // cc.logEx('intersects没有相交');
        return null;
    }
    else if (intersectsNodeArray.length === 1) {
        // cc.logEx('intersects单个相交', intersectsNodeArray[0], 
        //                               intersectsNodeArray[0].getWordPosition().x - this.getWordPosition().x);
        return intersectsNodeArray[0];
    }
    else if (intersectsNodeArray.length > 1) {
        var distance = Number.MAX_VALUE;
        var intersectsNode = null;
        intersectsNodeArray.forEach((node) => {
            var myWordPos = this.convertToWorldSpaceAR(cc.Vec2.ZERO);
            var nodeWordPos = node.convertToWorldSpaceAR(cc.Vec2.ZERO);
            var length = cc.v2(cc.pSub(myWordPos, nodeWordPos)).mag();
            if (length < distance) {
                distance = length;
                intersectsNode = node;
            }
        });
        // cc.logEx('intersects多个相交', intersectsNode, distance);
        return intersectsNode;
    }
}
// ------------------------------------ Component ------------------------------------
// 获取与当前节点同名的脚本
cc.Component.prototype.getScript = function() {
    return this.getComponent(this.node.name);
}
// 查找组件所在的node的子节点
cc.Component.prototype.find = function(path, componentType) {
    return this.node.find(path, componentType);
}
// 基于帧的for循环, 数组, callback, 每帧执行多少次num
cc.Component.prototype.forAsync = function(array, callback, endCallback, num) {
    this.forAsync_i(array.length, (i) => {
        var v = array[i];
        if (v !== undefined && v !== null) {
            callback(v, i);
        }
    }, endCallback, num);
}
// 基于帧的for循环, 次数， callback, 每帧执行多少次num
cc.Component.prototype.forAsync_i = function(length, callback, endCallback, num) {
    if (num === null || num === undefined) {
        num = 1;
    } else {
        num = Math.floor(num);
    }
    var i = 0;
    var framesIndex = 0;
    var framesMax = Math.ceil(length/num);
    this.schedule(() => {
        for (; i <= framesIndex * num && i < length; i++) {
            callback(i);
        }
        if (framesIndex === framesMax) {
            if (endCallback) endCallback();
        }
        framesIndex++;
    }, 0, framesMax, 0);
}
// 基于系统时间戳的定时器，返回内置回调函数，用于关闭
cc.Component.prototype.scheduleTime = function(cbk, interval) {
    var initTime = new Date().getTime();
    var lastTime = initTime;
    var intervalNum = 0;
    var _cbk = () => {
        var currentTime = new Date().getTime();
        var totalTime = ((currentTime - initTime)/1000);
        var num = totalTime/interval;
        var num_integer = Math.floor(num);
        var num_decimal = num - Math.floor(num);
        if (num_integer > intervalNum && num_decimal < 0.1) {
            var dt = (currentTime - lastTime)/1000;
            cbk.call(this, dt);
            lastTime = currentTime;
            intervalNum = num;
        }
    }
    this.schedule(_cbk, 0);
    return _cbk;
}
// ------------------------------------ Sprite ------------------------------------
// 动态加载url图片
cc.Sprite.prototype.loadUrlTexture = function(url, defaultImg) {
    if (this._initWidth == null) this._initWidth = this.node.width;
    if (this._initHeight == null) this._initHeight = this.node.height;
    if (this._initDefaultImg == null) this._initDefaultImg = this.spriteFrame;
    var errorFun = () => {
        if (defaultImg) {
            this.spriteFrame = defaultImg;
        }
        else if (this._initDefaultImg) {
            this.spriteFrame = this._initDefaultImg;
        }
        else {
            this.spriteFrame = null;
        }
    }
    if (!url) {
        errorFun();
        return;
    }
    var width = this._initWidth;
    var height = this._initHeight;
    cc.loadPng(url, (tex) => {
        if (!cc.isValid(this)) return;
        this.spriteFrame = new cc.SpriteFrame(tex);
        this.sizeMode = cc.Sprite.SizeMode.TRIMMED;
        var w = width / this.node.width;
        var h = height / this.node.height;
        if (w < h) {
            this.node.width = width;
            this.node.height = this.node.height * w;
        }
        else {
            this.node.height = height;
            this.node.width = this.node.width * h;
        }
    }, () => {
        if (!cc.isValid(this)) return;
        errorFun();
    });
}
// ------------------------------------ Prefab ------------------------------------
// 创建一个Prefab添加到prefabParent上，(注意：会先执行callback之后再执行Prefab的onLoad)
cc.Prefab.prototype.newTo = function(parentNode, newCallback) {
    if (!parentNode) return null;
    var newNode = cc.instantiate(this);
    if (newCallback) {
        var script = newNode.getComponent(newNode.name);
        newCallback(script);
    }
    parentNode.addChild(newNode);
    return newNode;
}
// ------------------------------------ Date ------------------------------------
// 时间格式化, new Date(timestamp).format("yyyy年MM月dd日hh时mm分ss秒")
// 毫秒格式化，new Date(milliseconds - 28800000).format("hh时mm分ss秒")
Date.prototype.format = function(format) {
    var o = {
        "M+": this.getMonth() + 1, //month
        "d+": this.getDate(), //day
        "h+": this.getHours(), //hour
        "m+": this.getMinutes(), //minute
        "s+": this.getSeconds(), //second
        "q+": Math.floor((this.getMonth() + 3) / 3), //quarter
        "S": this.getMilliseconds() //millisecond
    }

    if (/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    }

    for (var k in o) {
        if (new RegExp("(" + k + ")").test(format)) {
            format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
        }
    }
    return format;
}
// ------------------------------------ Math ------------------------------------
// 按照随机种子进行随机
// Math.seed = 5;
// Math.seededRandom = function(max, min) {
//     max = max || 1;
//     min = min || 0;
//     cc.log(Math.seed);
//     Math.seed = (Math.seed * 9301 + 49297) % 233280;
//     var rnd = Math.seed / 233280.0;
//     return min + rnd * (max - min);
// };
//随机n-m之间的数，包括 n, m
Math.rand = function(n, m) {
    var c = m - n + 1;
    return Math.floor(Math.random() * c + n)
}
// 随机n-m之间的浮点数，包括 n, m
Math.randf = function(n, m) {
    var c = m - n + 1;
    return Math.random() * c + n
}
// 返回一个随机的guid值
Math.guid = function() {
    function S4() {
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }
    return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
// 计算MD5值
Math.hex_md5 = hex_md5;
var hexcase = 0;
function hex_md5(a) {
    a = "" + a;
    if (a == "") return a;
    return rstr2hex(rstr_md5(str2rstr_utf8(a)))
}
function hex_hmac_md5(a, b) {
    return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a), str2rstr_utf8(b)))
}
function md5_vm_test() {
    return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72"
}
function rstr_md5(a) {
    return binl2rstr(binl_md5(rstr2binl(a), a.length * 8))
}
function rstr_hmac_md5(c, f) {
    var e = rstr2binl(c);
    if (e.length > 16) {
        e = binl_md5(e, c.length * 8)
    }
    var a = Array(16),
        d = Array(16);
    for (var b = 0; b < 16; b++) {
        a[b] = e[b] ^ 909522486;
        d[b] = e[b] ^ 1549556828
    }
    var g = binl_md5(a.concat(rstr2binl(f)), 512 + f.length * 8);
    return binl2rstr(binl_md5(d.concat(g), 512 + 128))
}
function rstr2hex(c) {
    try {
        hexcase
    } catch (g) {
        hexcase = 0
    }
    var f = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    var b = "";
    var a;
    for (var d = 0; d < c.length; d++) {
        a = c.charCodeAt(d);
        b += f.charAt((a >>> 4) & 15) + f.charAt(a & 15)
    }
    return b
}
function str2rstr_utf8(c) {
    var b = "";
    var d = -1;
    var a, e;
    while (++d < c.length) {
        a = c.charCodeAt(d);
        e = d + 1 < c.length ? c.charCodeAt(d + 1) : 0;
        if (55296 <= a && a <= 56319 && 56320 <= e && e <= 57343) {
            a = 65536 + ((a & 1023) << 10) + (e & 1023);
            d++
        }
        if (a <= 127) {
            b += String.fromCharCode(a)
        } else {
            if (a <= 2047) {
                b += String.fromCharCode(192 | ((a >>> 6) & 31), 128 | (a & 63))
            } else {
                if (a <= 65535) {
                    b += String.fromCharCode(224 | ((a >>> 12) & 15), 128 | ((a >>> 6) & 63), 128 | (a & 63))
                } else {
                    if (a <= 2097151) {
                        b += String.fromCharCode(240 | ((a >>> 18) & 7), 128 | ((a >>> 12) & 63), 128 | ((a >>> 6) & 63), 128 | (a & 63))
                    }
                }
            }
        }
    }
    return b
}
function rstr2binl(b) {
    var a = Array(b.length >> 2);
    for (var c = 0; c < a.length; c++) {
        a[c] = 0
    }
    for (var c = 0; c < b.length * 8; c += 8) {
        a[c >> 5] |= (b.charCodeAt(c / 8) & 255) << (c % 32)
    }
    return a
}
function binl2rstr(b) {
    var a = "";
    for (var c = 0; c < b.length * 32; c += 8) {
        a += String.fromCharCode((b[c >> 5] >>> (c % 32)) & 255)
    }
    return a
}
function binl_md5(p, k) {
    p[k >> 5] |= 128 << ((k) % 32);
    p[(((k + 64) >>> 9) << 4) + 14] = k;
    var o = 1732584193;
    var n = -271733879;
    var m = -1732584194;
    var l = 271733878;
    for (var g = 0; g < p.length; g += 16) {
        var j = o;
        var h = n;
        var f = m;
        var e = l;
        o = md5_ff(o, n, m, l, p[g + 0], 7, -680876936);
        l = md5_ff(l, o, n, m, p[g + 1], 12, -389564586);
        m = md5_ff(m, l, o, n, p[g + 2], 17, 606105819);
        n = md5_ff(n, m, l, o, p[g + 3], 22, -1044525330);
        o = md5_ff(o, n, m, l, p[g + 4], 7, -176418897);
        l = md5_ff(l, o, n, m, p[g + 5], 12, 1200080426);
        m = md5_ff(m, l, o, n, p[g + 6], 17, -1473231341);
        n = md5_ff(n, m, l, o, p[g + 7], 22, -45705983);
        o = md5_ff(o, n, m, l, p[g + 8], 7, 1770035416);
        l = md5_ff(l, o, n, m, p[g + 9], 12, -1958414417);
        m = md5_ff(m, l, o, n, p[g + 10], 17, -42063);
        n = md5_ff(n, m, l, o, p[g + 11], 22, -1990404162);
        o = md5_ff(o, n, m, l, p[g + 12], 7, 1804603682);
        l = md5_ff(l, o, n, m, p[g + 13], 12, -40341101);
        m = md5_ff(m, l, o, n, p[g + 14], 17, -1502002290);
        n = md5_ff(n, m, l, o, p[g + 15], 22, 1236535329);
        o = md5_gg(o, n, m, l, p[g + 1], 5, -165796510);
        l = md5_gg(l, o, n, m, p[g + 6], 9, -1069501632);
        m = md5_gg(m, l, o, n, p[g + 11], 14, 643717713);
        n = md5_gg(n, m, l, o, p[g + 0], 20, -373897302);
        o = md5_gg(o, n, m, l, p[g + 5], 5, -701558691);
        l = md5_gg(l, o, n, m, p[g + 10], 9, 38016083);
        m = md5_gg(m, l, o, n, p[g + 15], 14, -660478335);
        n = md5_gg(n, m, l, o, p[g + 4], 20, -405537848);
        o = md5_gg(o, n, m, l, p[g + 9], 5, 568446438);
        l = md5_gg(l, o, n, m, p[g + 14], 9, -1019803690);
        m = md5_gg(m, l, o, n, p[g + 3], 14, -187363961);
        n = md5_gg(n, m, l, o, p[g + 8], 20, 1163531501);
        o = md5_gg(o, n, m, l, p[g + 13], 5, -1444681467);
        l = md5_gg(l, o, n, m, p[g + 2], 9, -51403784);
        m = md5_gg(m, l, o, n, p[g + 7], 14, 1735328473);
        n = md5_gg(n, m, l, o, p[g + 12], 20, -1926607734);
        o = md5_hh(o, n, m, l, p[g + 5], 4, -378558);
        l = md5_hh(l, o, n, m, p[g + 8], 11, -2022574463);
        m = md5_hh(m, l, o, n, p[g + 11], 16, 1839030562);
        n = md5_hh(n, m, l, o, p[g + 14], 23, -35309556);
        o = md5_hh(o, n, m, l, p[g + 1], 4, -1530992060);
        l = md5_hh(l, o, n, m, p[g + 4], 11, 1272893353);
        m = md5_hh(m, l, o, n, p[g + 7], 16, -155497632);
        n = md5_hh(n, m, l, o, p[g + 10], 23, -1094730640);
        o = md5_hh(o, n, m, l, p[g + 13], 4, 681279174);
        l = md5_hh(l, o, n, m, p[g + 0], 11, -358537222);
        m = md5_hh(m, l, o, n, p[g + 3], 16, -722521979);
        n = md5_hh(n, m, l, o, p[g + 6], 23, 76029189);
        o = md5_hh(o, n, m, l, p[g + 9], 4, -640364487);
        l = md5_hh(l, o, n, m, p[g + 12], 11, -421815835);
        m = md5_hh(m, l, o, n, p[g + 15], 16, 530742520);
        n = md5_hh(n, m, l, o, p[g + 2], 23, -995338651);
        o = md5_ii(o, n, m, l, p[g + 0], 6, -198630844);
        l = md5_ii(l, o, n, m, p[g + 7], 10, 1126891415);
        m = md5_ii(m, l, o, n, p[g + 14], 15, -1416354905);
        n = md5_ii(n, m, l, o, p[g + 5], 21, -57434055);
        o = md5_ii(o, n, m, l, p[g + 12], 6, 1700485571);
        l = md5_ii(l, o, n, m, p[g + 3], 10, -1894986606);
        m = md5_ii(m, l, o, n, p[g + 10], 15, -1051523);
        n = md5_ii(n, m, l, o, p[g + 1], 21, -2054922799);
        o = md5_ii(o, n, m, l, p[g + 8], 6, 1873313359);
        l = md5_ii(l, o, n, m, p[g + 15], 10, -30611744);
        m = md5_ii(m, l, o, n, p[g + 6], 15, -1560198380);
        n = md5_ii(n, m, l, o, p[g + 13], 21, 1309151649);
        o = md5_ii(o, n, m, l, p[g + 4], 6, -145523070);
        l = md5_ii(l, o, n, m, p[g + 11], 10, -1120210379);
        m = md5_ii(m, l, o, n, p[g + 2], 15, 718787259);
        n = md5_ii(n, m, l, o, p[g + 9], 21, -343485551);
        o = safe_add(o, j);
        n = safe_add(n, h);
        m = safe_add(m, f);
        l = safe_add(l, e)
    }
    return Array(o, n, m, l)
}
function md5_cmn(h, e, d, c, g, f) {
    return safe_add(bit_rol(safe_add(safe_add(e, h), safe_add(c, f)), g), d)
}
function md5_ff(g, f, k, j, e, i, h) {
    return md5_cmn((f & k) | ((~f) & j), g, f, e, i, h)
}
function md5_gg(g, f, k, j, e, i, h) {
    return md5_cmn((f & j) | (k & (~j)), g, f, e, i, h)
}
function md5_hh(g, f, k, j, e, i, h) {
    return md5_cmn(f ^ k ^ j, g, f, e, i, h)
}
function md5_ii(g, f, k, j, e, i, h) {
    return md5_cmn(k ^ (f | (~j)), g, f, e, i, h)
}
function safe_add(a, d) {
    var c = (a & 65535) + (d & 65535);
    var b = (a >> 16) + (d >> 16) + (c >> 16);
    return (b << 16) | (c & 65535)
}
function bit_rol(a, b) {
    return (a << b) | (a >>> (32 - b))
};